package mth.rmclusterer;

import java.io.File;

public class BadNeighbors {
	/*
	 * Hier werden die verletzten Nebenbedingungen ermittelt. Dazu werden die per Mehrheits-
	 * entscheid aufgebauten Clusterlösungen mit den dazugehörigen Nachbarschaften verglichen.
	 * Der Vergleich basiert dabei auf angenommenen Klassen der Nachbarschaften. Es wird dabei
	 * diejenige Klasse angenommen, die den meisten Elementen in einer Nachbarschaft zugewiesen
	 * wurde. Stimmt eine Zuweisung in einer Nachbarschaft nicht mit der angenommenen Klasse
	 * überein, so wird das als Verletzung bewertet. Diese Art der Bewertung führt zwar zur
	 * doppelten Zählung von Verletzungen, ist aber einfach zu realisieren und durch die 
	 * Anwendung auf alle Testläufe in Relation wieder als fair zu bewerten.
	 */
	private RunNeighborhood[] neighborhoodsOfRun;
	private String[][] clusterResults;
	private String[] qValues;
	private String[] distMeasures;
	private String[] kValues;
	private int[] violatedConstraints;
	private double[] violationRatio;
	private String[] realQValue;
	private String[] nQValue;
	private String[] pairCount;
	
	BadNeighbors(VotedRunResult[] vrr) {
		fillNeighborhoods();
		if (vrr != null && vrr.length!=0) {
			clusterResults = new String[vrr.length][vrr[0].getAssignmentMix().length];
			qValues = new String[vrr.length];
			distMeasures = new String[vrr.length];
			kValues = new String[vrr.length];
			realQValue = new String[vrr.length];
			nQValue = new String[vrr.length];
			pairCount = new String[vrr.length];
			
			for (int a=0; a<vrr.length; a++) {
				qValues[a]=vrr[a].getQValue();
				distMeasures[a]=vrr[a].getDistanceMeasure();
				kValues[a]=vrr[a].getKValue();
				realQValue[a]=vrr[a].getRealQValue();
				nQValue[a]=vrr[a].getNQValue();
				pairCount[a]=vrr[a].getPairCount();
			}
		} else {
			System.out.println("ohne Werte keine Auswertung");
		}
		
		for (int a=0; a<vrr.length; a++) {
			for (int b=0; b<vrr[a].getAssignmentMix().length; b++) {
				clusterResults[a][b]=vrr[a].getAssignmentMix()[b];
			}
		}
		violatedConstraints=new int[vrr.length];
		violationRatio=new double[vrr.length];
	}
	
	private void calculateViolations(String[] supposedClasses, int v)	 {
		violatedConstraints[v]=0;
		violationRatio[v]=0.0;
		int amountOfMember=0;
		for (int a=0; a<neighborhoodsOfRun[v].getMember().length; a++) {
			for (int b=0; b<neighborhoodsOfRun[v].getMember()[a].getMember().length; b++) {
				if (!supposedClasses[a].equals(clusterResults[v][neighborhoodsOfRun[v].getMember()[a].getMember()[b]])) {
					violatedConstraints[v]++;
				}
				amountOfMember++;
			}
		}
		violationRatio[v]=(double)((double)violatedConstraints[v]/(double)(amountOfMember));
	}
	
	public void computeAmountOfBadNeighbors() {
		for (int a=0; a<clusterResults.length; a++) {
			//the different runs
			String[] supposedClasses = new String[neighborhoodsOfRun[a].getMember().length];
			for (int b=0; b<neighborhoodsOfRun[a].getMember().length; b++) {
				//go through all neighborhoods of each run
				String[] assignmentsPerNeighborhoodOfRun = new String[neighborhoodsOfRun[a].getMember()[b].getMember().length];
				for (int c=0; c<neighborhoodsOfRun[a].getMember()[b].getMember().length; c++) {
					assignmentsPerNeighborhoodOfRun[c]=clusterResults[a][neighborhoodsOfRun[a].getMember()[b].getMember()[c]];
				}
				supposedClasses[b]=getSupposedClass(assignmentsPerNeighborhoodOfRun);
			}
			calculateViolations(supposedClasses, a);
		}
	}
	
	private void fillNeighborhoods() {
		File directory = new File(Manager.PATH_TO_NEIGHBORHOODS);
		String[] files = directory.list();
		neighborhoodsOfRun = new RunNeighborhood[files.length];
		for (int a=0; a<files.length; a++) {
			neighborhoodsOfRun[a]=new RunNeighborhood(files[a]);
		}
	}
	
	private String getSupposedClass(String[] assignments) {
		String[] distinctClasses = new String[0];
		int[] countOfClass = new int[0];
		for (int a=0; a<assignments.length; a++) {
			if (!Manager.stringArrayContains(distinctClasses, assignments[a])) {
				distinctClasses=Manager.addStringToArray(distinctClasses, assignments[a]);
				countOfClass=Manager.addIntegerToArray(countOfClass, 1);
			} else {
				boolean breaker=false;
				for (int b=0; b<distinctClasses.length && !breaker; b++) {
					if (assignments[a].equals(distinctClasses[b])) {
						countOfClass[b]++;
						breaker = true;
					}
				}
			}
		}
		int maxCount=0;
		int maxCountPos=0;
		for (int a=0; a<countOfClass.length; a++) {
			if (maxCount<countOfClass[a]) {
				maxCount=countOfClass[a];
				maxCountPos=a;
			}
		}
		return distinctClasses[maxCountPos];
	}
	
	public String[] getQValues() {
		return qValues;
	}
	
	public String[] getKValues() {
		return kValues;
	}
	
	public String[] getDistanceMeasures() {
		return distMeasures; 
	}
	
	public String[] getRealQValues() {
		return realQValue;
	}
	
	public String[] getNQValues() {
		return nQValue;
	}
	
	public String[] getPairCounts() {
		return pairCount;
	}
	
	public int[] getViolatedConstraints() {
		return violatedConstraints;
	}
	
	public double[] getViolationRatio() {
		return violationRatio;
	}
}
